/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package idea.sfo.viewer.designer;


import designersfo.Cons.CellInfo.CellFormat;
import designersfo.Cons.CellInfo.CustomContentCellData;
import java.beans.IntrospectionException;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node.Property;
import org.openide.nodes.PropertySupport;
import org.openide.nodes.Sheet;
import org.openide.util.Exceptions;
import org.openide.util.lookup.Lookups;


/**
 *
 * @author renke002
 */
public class DesignerColNode extends AbstractNode
{

    /**
     * Properties contained (or derived from) the Cell-Data element.
     */
    public final static String[][] CELL_DATA_PROPS =
    {
        /*
         * @XmlAttribute(name = ) protected String ; @XmlAttribute(name =
         * "tab-order") protected String tabOrder; @XmlAttribute(name =
         * "background-color") protected String backgroundColor;
         * @XmlAttribute(name = ) protected String response; Property labelProp
         * = new PropertySupport.Reflection( dCol , String.class , , );
         */
        {
            "content-id" , "getContentId" , "setContentId"
        } ,
        {
            "relative-index" , "getRelativeIndex" , "setRelativeIndex"
        } ,
        {
            "response" , "getResponse" , "setResponse"
        }
    };
    /**
     * Attributes for <gids-designer:cell-info>.
     */
    public final static String[][] CELL_INFO_PROPS =
    {
        {
            "Joined horizontally" , "isJoinedHoriz" , null
        } ,
        {
            "# in horizontal set" , "getPosHoriz" , null
        } ,
        {
            "Joined vertically" , "isJoinedVert" , null
        } ,
        {
            "# in vertical set" , "getPosVert" , null
        }
    };
    /**
     * List of accessible border properties in Cons.CellInfo.CellFormat.
     */
    public final static String[][] CELL_FORMAT_BORDER =
    {
        /*
         * @( name = "border-rb-corner-radius" ) protected String
         * getBorderRbCornerRadius; @XmlAttribute( name =
         * "border-rt-corner-radius" ) protected String getBorderRtCornerRadius;
         * @XmlAttribute( name = "border-lt-corner-radius" ) protected String
         * getBorderLtCornerRadius; @XmlAttribute( name =
         * "border-lb-corner-radius" ) protected String getBorderLbCornerRadius;
         *
         */
        {
            "border-top-style" , "getBorderTopStyle" , null
        } ,
        {
            "border-top-color" , "getBorderTopColor" , null
        } ,
        {
            "border-top-width" , "getBorderTopWidth" , null
        } ,
        {
            "border-right-style" , "getBorderRightStyle" , null
        } ,
        {
            "border-right-color" , "getBorderRightColor" , null
        } ,
        {
            "border-right-width" , "getBorderRightWidth" , null
        } ,
        {
            "border-left-style" , "getBorderLeftStyle" , null
        } ,
        {
            "border-left-color" , "getBorderLeftColor" , null
        } ,
        {
            "border-left-width" , "getBorderLeftWidth" , null
        } ,
        {
            "border-bottom-style" , "getBorderBottomStyle" , null
        } ,
        {
            "border-bottom-color" , "getBorderBottomColor" , null
        } ,
        {
            "border-bottom-width" , "getBorderBottomWidth" , null
        }
    };
    /**
     * List of accessible properties in Cons.CellInfo.CellFormat.
     */
    public final static String[][] CELL_FORMAT_PROPS =
    {
        {
            "background-color" , "getBackgroundColor" , "setBackgroundColor"
        } ,
        {
            "font-family" , "getFontFamily" , null
        } ,
        {
            "font-size" , "getFontSize" , null
        } ,
        {
            "font-color" , "getFontColor" , null
        } ,
        {
            "font-style" , "getFontStyle" , null
        } ,
        {
            "font-weight" , "getFontWeight" , null
        } ,
        {
            "font-decoration" , "getFontDecoration" , null
        } ,
        {
            "font-rotation-angle" , "getFontRotationAngle" , null
        } ,
        {
            "margin-color" , "getMarginColor" , null
        } ,
        {
            "padding-bottom" , "getPaddingBottom" , null
        } ,
        {
            "padding-left" , "getPaddingLeft" , null
        } ,
        {
            "padding-top" , "getPaddingTop" , null
        } ,
        {
            "padding-right" , "getPaddingRight" , null
        } ,
        {
            "has-leader" , "getHasLeader" , null
        } ,
        {
            "has-goomer" , "getHasGoomer" , null
        } ,
        {
            "horz-alignment" , "getHorzAlignment" , null
        } ,
        {
            "vert-alignment" , "getVertAlignment" , null
        }
    };
    /**
     * Position of the attribute name in the Cell Format Properties array.
     */
    public final static int CELL_PROPS_NAME = 0;
    /**
     * Position of the getter function name in the Cell Format Properties array.
     */
    public final static int CELL_PROPS_GETTER = 1;
    /**
     * Position of the setter function name in the Cell Format Properties array.
     */
    public final static int CELL_PROPS_SETTER = 2;


    /**
     *
     * @param dCol
     * @throws IntrospectionException
     */
    public DesignerColNode( DesignerCol dCol ) throws IntrospectionException
    {
        super( Children.LEAF , Lookups.fixed( new Object[]
        {
            dCol
        } ) );
        this.setDisplayName( dCol.getName() );
    }


    /**
     * Since this class is extending an org.openide.nodes.AbstractNode, we need
     * to implement our own version of createSheet() to display the properties
     * we want the user to have access to.
     * <p/>
     * @return
     */
    @Override
    protected Sheet createSheet()
    {
        Sheet sheet = Sheet.createDefault();

        DesignerCol dCol = getLookup().lookup( DesignerCol.class );

        //
        sheet.put( this.createMainPropSheetSet( dCol ) );

        if ( dCol.containsCellInfo() )
        {
            // Add the CELL INFO properties to the sheet.
            sheet.put( this.createCellInfoSheetSet( dCol ) );

            if ( dCol.containsCellData() )
            {
                // Add the CELL DATA properties to the sheet.
                sheet.put( this.createCellDataPropSheetSet( dCol ) );
            }


            if ( dCol.containsCellFormat() )
            {
                // Cell-Format contains many fields, so it's best to display it on a
                // separate tab from Cell-Info & Cell-Data
                sheet.put(
                        createCellFormatPropSheetSet( dCol.getCellFormat() ) );
                /*
                 * separate function for the border properties.
                 */
                sheet.put( createCellFormatBorderPropSheetSet( dCol.
                        getCellFormat() ) );
            }
        }

        //
        return sheet;
    }


    /**
     *
     * @param cccd CustomContentCellData
     * @return
     */
    private Sheet.Set createCellDataPropSheetSet( DesignerCol dc )
    {
        //
        Sheet.Set cellDataSet = Sheet.createPropertiesSet();

        cellDataSet.setDisplayName( "Cell Data" );
        cellDataSet.setName( "CellData" );

        /*
         */
        Property<CustomContentCellData> prop;
        try
        {
            prop = new PropertySupport.Reflection(
                    dc ,
                    String.class ,
                    "getLabel" ,
                    "setLabel" );
            prop.setName( "content" );
            cellDataSet.put( prop );
        }
        catch ( NoSuchMethodException ex )
        {
            Exceptions.printStackTrace( ex );
        }

        CustomContentCellData cccd = dc.getCellData();
        //
        for ( int i = 0; i < DesignerColNode.CELL_DATA_PROPS.length; i++ )
        {
            try
            {
                /*
                 * DesignerColNode.CELL_FORMAT_PROPS[i] -> { ATTRIBUTE_NAME ,
                 * GETTER_FUNCTION_NAME , SETTER_FUNCTION_NAME , }
                 */
                prop = new PropertySupport.Reflection(
                        cccd ,
                        String.class ,
                        DesignerColNode.CELL_DATA_PROPS[i][DesignerColNode.CELL_PROPS_GETTER] ,
                        DesignerColNode.CELL_DATA_PROPS[i][DesignerColNode.CELL_PROPS_SETTER] );
                prop.setName(
                        DesignerColNode.CELL_DATA_PROPS[i][DesignerColNode.CELL_PROPS_NAME] );
                cellDataSet.put( prop );

            }
            catch ( NoSuchMethodException ex )
            {
                Exceptions.printStackTrace( ex );
            }
        }
        return cellDataSet;
    }


    /**
     * Create a sheet set to display cell formatting information.
     * <p/>
     * @param dCol
     * @return
     */
    private Sheet.Set createCellFormatPropSheetSet( CellFormat cellFormat )
    {
        /*
         * Create a new sheet set to display cell formatting information
         * separately from the rest of the cell properties.
         */
        Sheet.Set cellFormatSet = Sheet.createPropertiesSet();

        // this code will create a new tab under the properties window.
        // Cell-Format contains many fields, so it's best to display it on a
        // separate tab from Cell-Info & Cell-Data
        cellFormatSet.setValue( "tabName" , "Cell Format" );

        // due to the amount of information contained in a cell format object,
        // we'll split the cell format tab into separate sections, one of them
        // dedicated specifically to the border properties.
        cellFormatSet.setDisplayName( "Cell Style" );
        cellFormatSet.setName( "CellStyle" );

        /*
         * general cell formatting information
         */
        for ( int i = 0; i < DesignerColNode.CELL_FORMAT_PROPS.length; i++ )
        {
            try
            {
                /*
                 * DesignerColNode.CELL_FORMAT_PROPS[i] -> { ATTRIBUTE_NAME ,
                 * GETTER_FUNCTION_NAME , SETTER_FUNCTION_NAME , }
                 */
                Property<CellFormat> prop = new <CellFormat>PropertySupport.Reflection(
                        cellFormat ,
                        String.class ,
                        DesignerColNode.CELL_FORMAT_PROPS[i][DesignerColNode.CELL_PROPS_GETTER] ,
                        DesignerColNode.CELL_FORMAT_PROPS[i][DesignerColNode.CELL_PROPS_SETTER] );
                prop.setName(
                        DesignerColNode.CELL_FORMAT_PROPS[i][DesignerColNode.CELL_PROPS_NAME] );
                cellFormatSet.put( prop );

            }
            catch ( NoSuchMethodException ex )
            {
                Exceptions.printStackTrace( ex );
            }
        }
        return cellFormatSet;
    }


    /**
     *
     * @param cellFormat
     * @return
     */
    private Sheet.Set createCellFormatBorderPropSheetSet( CellFormat cellFormat )
    {
        /*
         * Create a new sheet set to display cell formatting information
         * separately from the rest of the cell properties.
         */
        Sheet.Set cellFormatSet = Sheet.createPropertiesSet();

        cellFormatSet.setValue( "tabName" , "Cell Format" );
        // This section is dedicated to the border specific properties, there are
        // so many that separating them form the general formatting info makes it
        // more readable.
        cellFormatSet.setDisplayName( "Cell Border" );
        cellFormatSet.setName( "CellBorder" );

        /*
         * Border-specific formatting information.
         */
        for ( int i = 0; i < DesignerColNode.CELL_FORMAT_BORDER.length; i++ )
        {
            try
            {
                /*
                 * DesignerColNode.CELL_FORMAT_PROPS[i] -> { ATTRIBUTE_NAME ,
                 * GETTER_FUNCTION_NAME , SETTER_FUNCTION_NAME , }
                 */
                Property<CellFormat> prop = new <CellFormat>PropertySupport.Reflection(
                        cellFormat ,
                        String.class ,
                        DesignerColNode.CELL_FORMAT_BORDER[i][DesignerColNode.CELL_PROPS_GETTER] ,
                        DesignerColNode.CELL_FORMAT_BORDER[i][DesignerColNode.CELL_PROPS_SETTER] );
                prop.setName(
                        DesignerColNode.CELL_FORMAT_BORDER[i][DesignerColNode.CELL_PROPS_NAME] );
                cellFormatSet.put( prop );

            }
            catch ( NoSuchMethodException ex )
            {
                Exceptions.printStackTrace( ex );
            }
        }
        return cellFormatSet;
    }


    /**
     * Create sheet set of properties based on the contents of the Cell-Info
     * element.
     * <p/>
     * @param dCol DesignerCol
     * @return
     */
    private Sheet.Set createCellInfoSheetSet( DesignerCol dCol )
    {
        //
        Sheet.Set cellInfoSet = Sheet.createPropertiesSet();

        cellInfoSet.setDisplayName( "Cell Info" );
        cellInfoSet.setName( "CellInfo" );

        for ( int i = 0; i < DesignerColNode.CELL_INFO_PROPS.length; i++ )
        {
            try
            {
                /*
                 * DesignerColNode.CELL_FORMAT_PROPS[i] -> { ATTRIBUTE_NAME ,
                 * GETTER_FUNCTION_NAME , SETTER_FUNCTION_NAME , }
                 */
                Property prop = new PropertySupport.Reflection(
                        dCol ,
                        String.class ,
                        DesignerColNode.CELL_INFO_PROPS[i][DesignerColNode.CELL_PROPS_GETTER] ,
                        DesignerColNode.CELL_INFO_PROPS[i][DesignerColNode.CELL_PROPS_SETTER] );
                prop.setName(
                        DesignerColNode.CELL_INFO_PROPS[i][DesignerColNode.CELL_PROPS_NAME] );
                cellInfoSet.put( prop );

            }
            catch ( NoSuchMethodException ex )
            {
                Exceptions.printStackTrace( ex );
            }
        }

        return cellInfoSet;

    }


    /**
     *
     * @param dCol
     * @return
     */
    private Sheet.Set createMainPropSheetSet( DesignerCol dCol )
    {
        //
        Sheet.Set propSet = Sheet.createPropertiesSet();

        try
        {
            Property nameProp = new PropertySupport.Reflection( dCol ,
                    String.class , "getName" , "setName" );
            Property rowNumProp = new PropertySupport.Reflection<>( dCol ,
                    Integer.class , "getRowNumber" , null );
            Property rowHeightProp = new PropertySupport.Reflection<>( dCol ,
                    Long.class , "getHeight" , null );
            Property rowWidthProp = new PropertySupport.Reflection<>( dCol ,
                    Long.class , "getWidth" , null );


            nameProp.setName( "ID" );
            rowNumProp.setName( "Row #" );
            rowHeightProp.setName( "Height" );
            rowWidthProp.setName( "Width" );

            propSet.put( nameProp );
            propSet.put( rowNumProp );
            propSet.put( rowHeightProp );
            propSet.put( rowWidthProp );
        }
        catch ( NoSuchMethodException ex )
        {
            Exceptions.printStackTrace( ex );
        }

        return propSet;
    }


    /**
     *
     * @param obj
     * @return
     */
    @Override
    public boolean equals( Object obj )
    {
        if ( obj == null )
        {
            return false;
        }
        if ( getClass() != obj.getClass() )
        {
            return false;
        }
        final DesignerColNode other = (DesignerColNode) obj;
        final DesignerCol dCol = this.getDesignerCol();

        if ( dCol.getRowNumber().equals( other.getRowNumber() )
                && dCol.getColNumber().equals( other.getColNumber() ) )
        {
            // both object have the same row and column numbers, IE. they
            // share the same location.
            return true;
        }
        else
        {
            return false;
        }
    }


    /**
     *
     * @return
     */
    public Integer getColNumber()
    {
        return this.getDesignerCol().getColNumber();
    }


    /**
     *
     * @return
     */
    public DesignerCol getDesignerCol()
    {
        return getLookup().lookup( DesignerCol.class );
    }


    /**
     *
     * @return
     */
    public Integer getRowNumber()
    {
        return this.getDesignerCol().getRowNumber();
    }


    /**
     *
     * @return
     */
    @Override
    public int hashCode()
    {
        DesignerCol dc = this.getDesignerCol();
        int col = dc.getColNumber();
        int row = dc.getRowNumber();
        return Integer.parseInt( col + "" + row );
    }


    /**
     * Makes the border of this element visible or invisible.
     * <p/>
     * @param visible
     */
    public void setBorderVisible( boolean visible )
    {
        getLookup().lookup( DesignerCol.class ).setBorderVisible( visible );
    }


    /**
     * Tells this element to set its 'selected' behavior.
     * <p/>
     * @param selected
     */
    public void setSelected( boolean selected )
    {
        getLookup().lookup( DesignerCol.class ).setSelected( selected );
    }

}
